home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / wdj0897.zip / DEFGEN.ZIP / DEFGEN.C
C/C++ Source or Header  |  1997-05-23  |  15KB  |  490 lines

  1. /* bcc32 -w -DSTRICT defgen.c
  2.  *      --OR--
  3.  * cl /W3 /DSTRICT defgen.c
  4.  */
  5. #include <ctype.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9.  
  10. #define TRUE        (1)
  11. #define FALSE       (0)
  12. #define MAX_LINE    (512)
  13. #define MAX_DEFS    (128)
  14. #define MAX_ARGS    (32)
  15. #define MAX_NEST    (32)
  16.  
  17. /* forward declarations                                     */
  18.  
  19. int     SetOptions(int Count, char** Args);
  20. void    Generate(const char* Filename);
  21. void    Usage(void);
  22.  
  23. /* Program options set via command-line parameters          */
  24.  
  25. int         Win16       = FALSE;    /* -Win16                   */
  26. int         BorImp      = FALSE;    /* -bi (Borland import)     */
  27. int         BorExp      = FALSE;    /* -be (Borland export)     */
  28. int         Microsoft   = TRUE;
  29. int         GenOrd      = FALSE;    /* -g (generate ordinals)   */
  30. int         StripOrd    = FALSE;    /* -s (strip ordinals)      */
  31. const char* Defs[MAX_DEFS];         /* -DName=val               */
  32. int         NDefs   = 0;
  33.  
  34. int     main(int Count, char** Args)
  35.     {
  36.     int     FirstFile = SetOptions(Count, Args);
  37.  
  38.     while(FirstFile < Count)
  39.         Generate(Args[FirstFile++]);
  40.     return EXIT_SUCCESS;
  41.     }
  42.  
  43. int     SetOptions(int Count, char** Args)
  44.     {
  45.     int iArg;
  46.     for(iArg = 1; iArg < Count; ++iArg)
  47.         {
  48.         if(Args[iArg][0] != '-')
  49.             break;
  50.         else switch(tolower(Args[iArg][1]))
  51.             {
  52.             case    'b' :   /* Borland import or export */
  53.                 if(!strcmpi(Args[iArg], "-bi"))
  54.                     {
  55.                     Microsoft   = FALSE;
  56.                     BorExp      = FALSE;
  57.                     BorImp      = TRUE;
  58.                     }
  59.                 else if(!strcmpi(Args[iArg], "-be"))
  60.                     {
  61.                     Microsoft   = FALSE;
  62.                     BorImp      = FALSE;
  63.                     BorExp      = TRUE;
  64.                     }
  65.                 else
  66.                     Usage();
  67.                 break;
  68.             case    's' :   StripOrd    = !StripOrd;    break;
  69.             case    'g' :   GenOrd      = !GenOrd;      break;
  70.             case    'd' :
  71.                 Defs[NDefs++]   = Args[iArg]+2;
  72.                 break;
  73.             case    'w' :
  74.                 if(!strcmpi(Args[iArg], "-win16"))
  75.                     {
  76.                     Win16   = TRUE;
  77.                     break;
  78.                     }
  79.                 else if(!strcmpi(Args[iArg], "-win32"))
  80.                     {
  81.                     Win16   = FALSE;
  82.                     break;
  83.                     }
  84.             default :       Usage();            break;
  85.             }
  86.         }
  87.     if(iArg >= Count)
  88.         Usage();
  89.  
  90.     return iArg;
  91.     }
  92. enum
  93.     {
  94.     STATE_SKIP  = 0x0001, STATE_IF = 0x0002,    STATE_ELSE = 0x0004,
  95.     STATE_ELSEIF= 0x0008, STATE_ENDIF = 0x0010, STATE_COMMAND=0x0020,
  96.     STATE_ERR   = 0x8000
  97.     };
  98.  
  99. const char*LineType(const char* Line, int* Type)
  100.     {
  101.     int     Result  = 0;
  102.     int     Len=0;
  103.  
  104.     if(*Line == '!')
  105.         {
  106.         ++Line;
  107.         while(isspace(*Line))   /* skip white space */
  108.             ++Line;
  109.         if(!strnicmp(Line, "if", 2) && isspace(Line[Len=2]))
  110.             Result  = STATE_IF;
  111.         else if(!strnicmp(Line, "else", 4) && isspace(Line[Len=4]))
  112.             Result  = STATE_ELSE;
  113.         else if(!strnicmp(Line, "elseif", 6) && isspace(Line[Len=6]))
  114.             Result  = STATE_ELSEIF;
  115.         else if(!strnicmp(Line, "endif", 5) && isspace(Line[Len=5]))
  116.             Result  = STATE_ENDIF;
  117.         else
  118.             Result  = STATE_ERR;
  119.         }
  120.     else if(Line[0] && !isspace(Line[0]))
  121.         Result  = STATE_COMMAND;
  122.  
  123.     *Type   = Result;
  124.     return Line + Len;
  125.     }
  126.  
  127. size_t    ExpandMacro(const char* Arg, char* Out)
  128.     {
  129.     size_t  NameLen;
  130.     int     i;
  131.     char    Name[MAX_LINE];
  132.  
  133.     *Out    = '\0';
  134.     Arg += 2;
  135.     for(i = 0; *Arg && *Arg != ')'; ++i)
  136.         Name[i]     = *Arg++;
  137.     Name[i] = '\0';
  138.     NameLen = strlen(Name);
  139.  
  140.     /* use command-line definition, if found        */
  141.     for(i = 0; i < NDefs; ++i)
  142.         if(!strncmp(Defs[i], Name, NameLen))
  143.             {
  144.             strcpy(Out, Defs[i]+NameLen+1);
  145.             break;
  146.             }
  147.     /* else, use environment definition, if found   */
  148.     if(i >= NDefs)
  149.         {
  150.         char *EnvDef = getenv(Name);
  151.         if(EnvDef)
  152.             strcpy(Out, EnvDef);
  153.         else    /* else, refer to builtins  */
  154.             {
  155.             int *Value = 0;
  156.             if(!strcmpi(Name, "Win16"))
  157.                 Value   = &Win16;
  158.             else if(!strcmpi(Name, "Win32"))
  159.                 Value   = &Win16;
  160.             else if(!strcmpi(Name, "BorImp"))
  161.                 Value   = &BorImp;
  162.             else if(!strcmpi(Name, "BorExp"))
  163.                 Value   = &BorExp;
  164.             else if(!strcmpi(Name, "StripOrd"))
  165.                 Value   = &StripOrd;
  166.             else if(!strcmpi(Name, "GenOrd"))
  167.                 Value   = &GenOrd;
  168.             if(Value)
  169.                 if(!strcmpi(Name, "Win32"))
  170.                     strcpy(Out, (!*Value) ? "1" : "0");
  171.                 else
  172.                     strcpy(Out, *Value ? "1" : "0");
  173.             }
  174.         }
  175.     return NameLen + 3;
  176.     }
  177.  
  178. int     GetCondition(const char* Str)
  179.     {
  180.     int     Condition   = FALSE;
  181.     int     Not = FALSE;
  182.     char    Expanded[MAX_LINE];
  183.  
  184.     while(isspace(*Str))    ++Str;  /* skip white space */
  185.     if(*Str == '!')
  186.         {
  187.         Not     = TRUE;
  188.         ++Str;
  189.         while(isspace(*Str))    ++Str;  /* skip white space */
  190.         }
  191.     if(*Str)
  192.         {
  193.         char* Out = Expanded;
  194.         while(*Str && !isspace(*Str))
  195.             if(*Str == '$' && Str[1] == '(')
  196.                 {
  197.                 size_t Len  = ExpandMacro(Str, Out);
  198.                 Str        += Len;
  199.                 Out        += strlen(Out);
  200.                 }
  201.             else
  202.                 *Out++  = *Str++;
  203.         *Out    = '\0';
  204.         if(Expanded[0] && strcmp(Expanded, "0"))
  205.             Condition    = TRUE;
  206.         }
  207.     return Not ? !Condition : Condition;
  208.     }
  209.  
  210. void    FixName(const char*In, char* Out, int Cdecl)
  211.     {
  212.     char    Upper[MAX_LINE];
  213.     strcpy(Upper, In);
  214.     strupr(Upper);
  215.     if(!Cdecl)
  216.         if(Win16)
  217.             strcpy(Out, Upper);
  218.         else
  219.             strcpy(Out, In);
  220.     else
  221.         if(Win16)
  222.             sprintf(Out, "_%s", In, Upper);
  223.         else if(BorExp)
  224.             sprintf(Out, "%s=_%s", In, In);
  225.         else if(BorImp)
  226.             sprintf(Out, "_%s=%s", In, In);
  227.         else
  228.             sprintf(Out, "%s", In);
  229.     }
  230.  
  231. void    DoExport(char* Line)
  232.     {
  233.     static int  OrdCount = 0;
  234.     static char OrdStr[8];
  235.     int         Unicode = FALSE;
  236.     int         Cdecl   = FALSE;
  237.     int         ResName = FALSE;
  238.     int         NoName  = FALSE;
  239.     int         NoData  = FALSE;
  240.     int         Data    = FALSE;
  241.     int         Private = FALSE;
  242.     const char* FuncName= 0;
  243.     const char* Ordinal = 0;
  244.     const char* ParmCnt = 0;
  245.  
  246.     char*       Rover   = Line;
  247.  
  248.     while(*Rover)
  249.         {
  250.         char* Token;
  251.         while(isspace(*Rover)) ++Rover;     /* skip white space */
  252.         if(*Rover)
  253.             {
  254.             Token  = Rover;
  255.             while(*Rover && !isspace(*Rover))   ++Rover;
  256.             if(*Rover)
  257.                 *Rover++    = '\0';
  258.             if(!strcmpi(Token, "residentname"))
  259.                 ResName     = TRUE;
  260.             else if(!strcmpi(Token, "nodata"))
  261.                 NoData      = TRUE;
  262.             else if(!strcmpi(Token, "noname"))
  263.                 NoName      = TRUE;
  264.             else if(!strcmpi(Token, "data"))
  265.                 Data        = TRUE;
  266.             else if(!strcmpi(Token, "private"))
  267.                 Private     = TRUE;
  268.             else if(!strcmpi(Token, "-U"))
  269.                 Unicode     = TRUE;
  270.             else if(!strcmpi(Token, "-c"))
  271.                 Cdecl     = TRUE;
  272.             else if(*Token == '@' && isdigit(Token[1]))
  273.                 {
  274.                 if(StripOrd)    /* stripping takes precedence   */
  275.                     ;
  276.                 else
  277.                     Ordinal     = Token;
  278.                 }
  279.             else if(isdigit(*Token))
  280.                 ParmCnt     = Token;
  281.             else if(FuncName)
  282.                 {
  283.                 fprintf(stderr,
  284.                     "Unknown export param: '%s'\n", Token);
  285.                 Usage();
  286.                 }
  287.             else
  288.                 FuncName    = Token;
  289.             }
  290.         }
  291.     if(FuncName)
  292.         {
  293.         int     Times = (!Win16 && Unicode)? 2 : 1;
  294.         int     i;
  295.         char*   Suffix[] = {"A", "W"};
  296.         if(GenOrd)  /* if generating our own ordinals   */
  297.             {
  298.             sprintf(OrdStr, "@%d", ++OrdCount);
  299.             Ordinal     = OrdStr;
  300.             }
  301.         for(i = 0; i < Times; ++i)
  302.             {
  303.             char    UniName[MAX_LINE];
  304.             char    FixedName[MAX_LINE];
  305.             char    FixedOrd[32];
  306.             strcpy(UniName, FuncName);
  307.             if(Ordinal)
  308.                 strcpy(FixedOrd, Ordinal);
  309.             if(Times > 1)
  310.                 {
  311.                 strcat(UniName, Suffix[i]);
  312.                 if(Ordinal && i > 0)
  313.                     sprintf(FixedOrd, "@%d", GenOrd ? ++OrdCount :
  314.                         atoi(Ordinal+1)+1);
  315.                 }
  316.             if(Ordinal && NoName && (Microsoft || !Win16))
  317.                 strcat(FixedOrd, " NONAME");
  318.             FixName(UniName, FixedName, Cdecl);
  319.             printf("    %s %s %s %s %s %s %s\n",
  320.                     FixedName,
  321.                     Ordinal     ? FixedOrd      : "",
  322.                     (ResName&&!NoName&&!(Microsoft&&!Win16))
  323.                                 ?"RESIDENTNAME" : "",
  324.                     (NoData&&!(Microsoft&&!Win16))
  325.                                 ? "NODATA"      : "",
  326.                     (Data&&Microsoft&&!Win16)
  327.                                 ? "DATA"        : "",
  328.                     (ParmCnt&&!(Microsoft&&!Win16))
  329.                                 ? ParmCnt       : "",
  330.                     (Private&&Microsoft)
  331.                                 ? "PRIVATE"     : ""
  332.                     );
  333.             }
  334.         }
  335.     else
  336.         printf(";%s", Line);
  337.     }
  338.  
  339. void    Generate(const char* FileName)
  340.     {
  341.     extern  int    DoLine(char*Line, int State);
  342.     char    Line[MAX_LINE];
  343.     int     DoingExports    = FALSE;
  344.     int     Stack[MAX_NEST];
  345.     int     Sp              = -1;
  346.     int     Skipping        = 0x0000;
  347.     FILE*   In              = fopen(FileName, "r");
  348.  
  349.     if(!In)     /* if can't open file, notify and exit      */
  350.         {
  351.         perror(FileName);
  352.         Usage();
  353.         }
  354.     while(fgets(Line, sizeof(Line)-1, In))
  355.         {
  356.         int         Type;
  357.         const char* Args;
  358.         Args    = LineType(Line, &Type);
  359.         if(Type == STATE_IF)
  360.             {
  361.             Stack[++Sp]     = Skipping;
  362.             Stack[++Sp]     = STATE_IF;
  363.             if(!Skipping)
  364.                 Skipping    = !GetCondition(Args);
  365.             Stack[Sp]      |= Skipping;
  366.             }
  367.         else if(Type == STATE_ELSE)
  368.             {
  369.             if(Sp < 1 || !(Stack[Sp]&STATE_IF))
  370.                 fprintf(stderr, "%s: !else with no matching !if\n",
  371.                     FileName);
  372.             else
  373.                 {
  374.                 Stack[Sp]   = (Stack[Sp] ^ STATE_IF) | STATE_ELSE;
  375.                 Skipping    = !(Stack[Sp]&STATE_SKIP);
  376.                 }
  377.             }
  378.         else if(Type == STATE_ELSEIF)
  379.             {
  380.             if(Sp < 1 || !(Stack[Sp]&STATE_IF))
  381.                 fprintf(stderr, "%s: !elseif with no matching !if\n",
  382.                     FileName);
  383.             else 
  384.                 {
  385.                 Skipping    = STATE_SKIP;
  386.                 if(Stack[Sp]&STATE_SKIP)
  387.                     {
  388.                     if(GetCondition(Args))
  389.                         {
  390.                         Stack[Sp]   ^= STATE_SKIP;
  391.                         Skipping    = FALSE;
  392.                         }
  393.                     }
  394.                 }
  395.             }
  396.         else if(Type == STATE_ENDIF)
  397.             {
  398.             if(Sp < 1 || !(Stack[Sp]&(STATE_IF|STATE_ELSE)))
  399.                 fprintf(stderr, "%s: !endif with no matching !if\n",
  400.                     FileName);
  401.             else
  402.                 {
  403.                 --Sp;           /* pop off if/else  */
  404.                 Skipping    = Stack[Sp--];
  405.                 }
  406.             }
  407.         else if(Type == STATE_ERR)
  408.             fprintf(stderr, "%s: Unknown directive (%s)\n",
  409.                 FileName, Line);
  410.         else if(!Skipping)
  411.             {
  412.             if(DoingExports)
  413.                 DoExport(Line);
  414.             else
  415.                 {
  416.                 char    Macro[MAX_LINE];
  417.                 char*   In = Line;
  418.  
  419.                 while(*In)
  420.                     {
  421.                     if(In[0] == '$' && In[1] == '(')
  422.                         {
  423.                         size_t  Len = ExpandMacro(In, Macro);
  424.                         In         += Len;
  425.                         printf("%s", Macro);
  426.                         }
  427.                     else
  428.                         putchar(*In++);
  429.                     }
  430.                 }
  431.             if(Type == STATE_COMMAND)
  432.                 DoingExports = !strncmp(Line, "EXPORTS", 7);
  433.             }
  434.         }
  435.  
  436.     fclose(In);
  437.     }
  438.  
  439. void    PutArg(const char* Arg)
  440.     {
  441.     while(*Arg)
  442.         if(*Arg == '$' && Arg[1] == '(')
  443.             {
  444.             size_t  NameLen;
  445.             int     i;
  446.             char    Name[MAX_LINE];
  447.             Arg += 2;
  448.             for(i = 0; *Arg && *Arg != ')'; ++i)
  449.                 Name[i]     = *Arg++;
  450.             Name[i] = '\0';
  451.             NameLen = strlen(Name);
  452.             if(*Arg == ')')
  453.                 ++Arg;
  454.             /* use command-line definition, if found        */
  455.             for(i = 0; i < NDefs; ++i)
  456.                 if(!strncmp(Defs[i], Name, NameLen))
  457.                     {
  458.                     printf("%s", Defs[i]+NameLen+1);
  459.                     break;
  460.                     }
  461.             /* else, use environment definition, if found   */
  462.             if(i >= NDefs)
  463.                 {
  464.                 char *EnvDef = getenv(Name);
  465.                 if(EnvDef)
  466.                     printf("%s", EnvDef);
  467.                 }
  468.             }
  469.         else
  470.             putchar(*Arg++);
  471.     }
  472.  
  473. void    Usage(void)
  474.     {
  475.     fprintf(stderr,
  476.         "Usage:\n"
  477.         "    defgen {-options} infile1 {... infilen}\n"
  478.         "Where:\n"
  479.         "    -be        <- for Borland exports\n"
  480.         "    -bi        <- for Borland import library\n"
  481.         "    -DName=val <- Define text macro\n"
  482.         "    -g         <- generate ordinals\n"
  483.         "    -s         <- strip existing ordinals\n"
  484.         "    -Win16     <- produce Win16 .DEF file\n"
  485.         "(writes to standard output, default is 32-bit VC++)\n"
  486.         );
  487.     exit(EXIT_FAILURE);
  488.     }
  489.  
  490.